package com.exrobot.module.rbt.service.mqtt;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.exrobot.framework.common.exception.ErrorCode;
import com.exrobot.framework.common.util.date.LocalDateTimeUtils;
import com.exrobot.module.rbt.controller.admin.order.vo.OrderPageReqVO;
import com.exrobot.module.rbt.controller.admin.order.vo.OrderSaveReqVO;
import com.exrobot.module.rbt.controller.admin.orderitem.vo.OrderItemPageReqVO;
import com.exrobot.module.rbt.controller.admin.robotoperationlog.vo.RobotOperationLogSaveReqVO;
import com.exrobot.module.rbt.controller.admin.robottask.vo.RobotTaskSaveReqVO;
import com.exrobot.module.rbt.controller.app.vo.*;
import com.exrobot.module.rbt.dal.dataobject.canteeninfo.CanteenInfoDO;
import com.exrobot.module.rbt.dal.dataobject.order.OrderDO;
import com.exrobot.module.rbt.dal.dataobject.orderitem.OrderItemDO;
import com.exrobot.module.rbt.dal.dataobject.robotinfo.RobotInfoDO;
import com.exrobot.module.rbt.dal.redis.RbtRedisDAO;
import com.exrobot.module.rbt.enums.*;
import com.exrobot.module.rbt.framework.util.CommonUtils;
import com.exrobot.module.rbt.mq.message.deliveryFood.DeliveryFoodMessage;
import com.exrobot.module.rbt.mq.message.order.OrderItemMessage;
import com.exrobot.module.rbt.mq.message.order.OrderMessage;
import com.exrobot.module.rbt.mq.message.prepareFood.PrepareFoodItemMessage;
import com.exrobot.module.rbt.mq.message.prepareFood.PrepareFoodMessage;
import com.exrobot.module.rbt.mq.producer.deliveryFood.DeliveryFoodProducer;
import com.exrobot.module.rbt.mq.producer.order.OrderProducer;
import com.exrobot.module.rbt.mq.producer.prepareFood.PrepareFoodProducer;
import com.exrobot.module.rbt.service.canteeninfo.CanteenInfoService;
import com.exrobot.module.rbt.service.order.OrderService;
import com.exrobot.module.rbt.service.robotScheduler.RobotSchedulerService;
import com.exrobot.module.rbt.service.robotoperationlog.RobotOperationLogService;
import com.exrobot.module.rbt.service.robottask.RobotTaskService;
import jakarta.annotation.Resource;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.exrobot.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.exrobot.framework.common.util.collection.CollectionUtils.convertList;

@Slf4j
@Service
public class MqttMessageServiceImpl implements MqttMessageService {

    @Autowired
    private MqttPahoClientFactory mqttClientFactory; // 注入配置好的客户端工厂

    @Value("${spring.mqtt.client-id}")
    private String clientId;

    @Value("${spring.mqtt.default-topic}")
    private String defaultTopic;

    @Resource
    private RobotOperationLogService robotOperationLogService;

    @Resource
    private RobotTaskService taskService;

    @Resource
    private RbtRedisDAO redisDAO;

    @Resource
    private OrderProducer orderProducer;

    @Resource
    private PrepareFoodProducer prepareFoodProducer;

    @Resource
    private DeliveryFoodProducer deliveryFoodProducer;
    /**
     * 发送消息到默认主题
     */
    @Override
    public void sendToMqtt(String payload) throws MqttException {
        sendToMqtt(defaultTopic, 1, payload); // 默认QoS为1
    }

    /**
     * 发送消息到指定主题（默认QoS为1）
     */
    @Override
    public void sendToMqtt(String topic, String payload) throws MqttException {
        sendToMqtt(topic, 1, payload);
    }

    /**
     * 发送消息到指定主题并指定QoS
     */
    @Override
    public void sendToMqtt(String topic, int qos, String payload) throws MqttException {
        // 使用IMqttClient接口接收，解决类型不兼容问题
        IMqttClient client = mqttClientFactory.getClientInstance(
                mqttClientFactory.getConnectionOptions().getServerURIs()[0],
                clientId + "_sender_" + System.currentTimeMillis()
        );

        try {
            if (!client.isConnected()) {
                client.connect(mqttClientFactory.getConnectionOptions());
            }

            MqttMessage message = new MqttMessage();
            message.setPayload(payload.getBytes());
            message.setQos(qos);

            client.publish(defaultTopic+topic, message);
            log.info("[MQTT-发布成功] - 主题: " + defaultTopic+topic + ", 内容: " + payload);
        } catch (MqttException e) {
            log.info("[MQTT-发布失败] - 主题: " + defaultTopic+topic + ", 消息: " + e.getMessage());
            throw e;
        }
    }

    @Override
    public void sendCommonTask(String sn, List<CommonTaskVO> list) {
        MqCommonVO<List<CommonTaskVO>> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(list);
        String topic = String.format(MqttTopicPubEnum.COMMON_TASK.getTypeVal(), sn);
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendChargeTask(String sn) {
        MqCommonVO<Integer> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(1);
        String topic = String.format(MqttTopicPubEnum.CHARGE_TASK.getTypeVal(), sn);
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendUvlampTask(String sn, UvlampTaskVO uvlampTaskVO) {
        MqCommonVO<UvlampTaskVO> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(uvlampTaskVO);
        String topic = String.format(MqttTopicPubEnum.UVLAMP_TASK.getTypeVal(), sn);
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendMealCodeDelete(String sn, MealCodeDeleteVO mealCodeDeleteVO) {
        MqCommonVO<MealCodeDeleteVO> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(mealCodeDeleteVO);
        String topic = String.format(MqttTopicPubEnum.MEAL_CODE_DELETE.getTypeVal(), sn);
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendMealCode(String sn, MealCodeVO mealCodeVO) {
        MqCommonVO<MealCodeVO> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(mealCodeVO);
        String topic = String.format(MqttTopicPubEnum.MEAL_CODE.getTypeVal(), sn);
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendOrderDelivery(List<OrderDeliveryVO> list) {
        MqCommonVO<List<OrderDeliveryVO>> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(list);
        String topic = MqttTopicPubEnum.ORDER_DELIVERY.getTypeVal();
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void sendMiniproMessage(MiniproMessageVO messageVO) {
        MqCommonVO<MiniproMessageVO> mqCommonVO = new MqCommonVO<>();
        mqCommonVO.setTs(System.currentTimeMillis());
        mqCommonVO.setValues(messageVO);
        String topic = MqttTopicPubEnum.MINIPRO_MESSAGE.getTypeVal();
        try {
            sendToMqtt(topic, 1, JSON.toJSONString(mqCommonVO));
        } catch (MqttException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 处理Mqtt消息
     *
     * @param topic 消息
     * @param payload 消息内容
     */
    @Override
    public void messageHanding(String topic, String payload) {
        JSONObject jsonObject = null;
        String sn = "";
        RobotOperationLogSaveReqVO saveReqVO = new RobotOperationLogSaveReqVO();
        saveReqVO.setTopic(topic);
        saveReqVO.setInfo(payload);
        try {
            jsonObject = JSON.parseObject(payload);
            if (!jsonObject.containsKey("values") || !jsonObject.containsKey("ts")) {
                saveReqVO.setType(RbtLogTypeEnum.OTHER.getTypeVal());
                saveReqVO.setTitle("数据错误");
                robotOperationLogService.createRobotOperationLog(saveReqVO);
                return;
            }
            JSONObject valJson = jsonObject.getJSONObject("values");
            saveReqVO.setTs(jsonObject.getLong("ts"));
            // 可以根据不同主题实现不同的业务逻辑
            MqttTopicSubEnum topicSubEnum = MqttTopicSubEnum.getMqttEnum(topic);
            if(topicSubEnum == null) {
                saveReqVO.setType(RbtLogTypeEnum.OTHER.getTypeVal());
                saveReqVO.setTitle("数据错误");
                saveReqVO.setType(RbtLogTypeEnum.OTHER.getTypeVal());
                robotOperationLogService.createRobotOperationLog(saveReqVO);
                return;
            }
            sn = valJson.getString("sn");
            switch (topicSubEnum) {
                case LOG_UPLOAD:
                    Integer boxSn = valJson.getInteger("value");
                    String title = valJson.containsKey("title") ? valJson.getString("title") : "错误上报";
                    saveReqVO.setTitle(String.format("%s - %s",title,boxSn.toString()))
                            .setType(valJson.getString("type"))
                            .setValue(valJson.getString("info"));
                    if (saveReqVO.getType().equals("lock")) {
                        redisDAO.setLockErr(sn, boxSn);
                    }
                    break;
                case PREPARE_FOOD:
                    Integer status = valJson.getInteger("status");
                    saveReqVO.setStatus(status)
                            .setType(RbtLogTypeEnum.PLACE.getTypeVal())
                            .setValue(valJson.getString("value"))
                            .setTitle("配餐 - " + (status.equals(1) ? "结束" : "开始"));
                    PrepareFoodMessage prepareFoodMessage = JSON.parseObject(valJson.toJSONString(),PrepareFoodMessage.class);
                    prepareFoodProducer.sendPrepareFoodMessage(prepareFoodMessage);
                    break;
                case TASK_SITE:
                    Integer siteStatus = valJson.getInteger("status");
                    saveReqVO.setType(RbtLogTypeEnum.SITE.getTypeVal())
                            .setValue(valJson.getString("siteId"))
                            .setTitle((siteStatus.equals(1) ? "离开" : "到达") + " - 点位")
                            .setStatus(siteStatus);
                    redisDAO.setPoint(sn, saveReqVO.getValue());
                    break;
                case UVLAMP_STATUS:
                    Integer uvlampStatus = valJson.getInteger("status");
                    saveReqVO.setType(RbtLogTypeEnum.UVLAMP.getTypeVal())
                            .setValue(valJson.getString("taskId"))
                            .setTitle("紫外线开启状态")
                            .setStatus(uvlampStatus);
                    taskService.updateRobotTaskStatus(saveReqVO.getSn(), RbtTaskTypeEnum.UVLAMP.getTypeVal(), uvlampStatus);
                    break;
                case CHARGE_TASK:
                    saveReqVO.setType(RbtLogTypeEnum.CHARGE.getTypeVal())
                            .setValue(valJson.getString("value"))
                            .setTitle("餐车充电任务");
                    break;
                case OPERATION:
                    Integer optStatus = valJson.getInteger("status");
                    String typeVal = valJson.getString("type");
                    String typeName = RbtLogTypeEnum.getName(typeVal);
                    saveReqVO.setType(typeVal)
                            .setTitle(typeName + " - " + (optStatus.equals(1) ? "结束" : "开始"))
                            .setStatus(optStatus);
                    taskService.updateRobotTaskStatus(saveReqVO.getSn(), RbtTaskTypeEnum.CHECK.getTypeVal(), optStatus);
                    if (RbtLogTypeEnum.CHECK.getTypeVal().equals(typeVal)) {
                        redisDAO.deleteLockErr(saveReqVO.getSn());
                    }
                    break;
                case DELIVERY_FOOD:
                    saveReqVO.setType(RbtLogTypeEnum.DELIVERY_FOOD.getTypeVal())
                            .setValue(valJson.getString("siteId")+" - "+valJson.getString("code"))
                            .setTitle("送餐 - 完成")
                            .setStatus(1);
                    DeliveryFoodMessage deliveryFoodMessage = JSON.parseObject(valJson.toJSONString(),DeliveryFoodMessage.class);
                    deliveryFoodProducer.sendDeliveryFoodMessage(deliveryFoodMessage);
                    break;
                case ORDER_CREATE:
                    saveReqVO.setType(RbtLogTypeEnum.ORDER.getTypeVal())
                            .setTitle("创建订单")
                            .setStatus(0);
                    OrderMessage orderMessage = JSON.parseObject(valJson.toJSONString(),OrderMessage.class);
                    orderProducer.sendOrderMessage(orderMessage);
                    break;
                default:
                    saveReqVO.setType(RbtLogTypeEnum.OTHER.getTypeVal())
                            .setTitle("未找到TOPIC")
                            .setInfo(payload)
                            .setStatus(1);
                    break;
            }
            saveReqVO.setSn(sn);
            saveReqVO.setCreateTime(LocalDateTime.now());
            robotOperationLogService.createRobotOperationLog(saveReqVO);
        } catch (Exception e) {
            saveReqVO.setSn(sn);
            saveReqVO.setType(RbtLogTypeEnum.OTHER.getTypeVal());
            saveReqVO.setTitle("数据错误");
            saveReqVO.setInfo(payload);
            saveReqVO.setStatus(1);
            saveReqVO.setCreateTime(LocalDateTime.now());
            robotOperationLogService.createRobotOperationLog(saveReqVO);
            throw exception(new ErrorCode(500,e.getMessage()));
        }
    }
}